/*
 * $Id: Mutex.java 9 2006-03-08 10:21:59Z wjx $
 */
package com.someok.utils;

/**
 * Class that provides fast mutual exclusion using Leslie Lamport's "Fast
 * Mutal Exclusion" algorithm.
 *
 * This class does not use the built-in synchronization monitor primitives of
 * the Java language, thus allowing for proper synchronization across method
 * calls.
 *
 * Object (i.e. resource) that uses Mutex must be accessed only between
 * lock() and unlock().
 *
 * <p><a href="Mutex.java.html"><i>View Source</i></a></p>
 *
 * @version $Revision: 9 $ $Date: 2006-03-08 18:21:59 +0800 (星期三, 08 三月 2006) $
 */
public class Mutex {

	/* volatile modifier are used in order to inform the compiler not to do
	clever caching tricks and assumptions regarding their contents. */
	private volatile Thread x;
	private volatile Thread y;
	/**
	 * Constructor.
	 */
	public Mutex() {
		this.y = null;
		this.x = null;
	}

	/**
	 * Aquire mutex. When this method returns, the calling thread have the mutex,
	 * and is can for all practical purposes be said to be within whatever
	 * critical region this mutex instance is supposed to protect.
	 *
	 * The method uses the calling thread's thread reference (obtained via
	 * Thread.currentThread()) to uniquely identify a thread.
	 */
	public void lock() {
		Thread _current = Thread.currentThread();
		while (true) {
			this.x = _current;
			if (this.y != null) {
				Thread.yield();
				continue;
			}
			this.y = _current;
			if (this.x != _current) {
				Thread.yield();
				if (this.y != _current) {
					Thread.yield();
					continue;
				}
			}
			break;
		}
	}

	/**
	 * Release an aquired mutex. This particular implementation will allow both
	 * releases from non-owning threads, as well as multiple releases.
	 */
	public void unlock() {
		this.y = null;								// release mutex
	}

	/**
	 * Probe the mutex state. Note that this is inaccurate, and can only serve as
	 * an indication of whether the mutex is in use or not.
	 *
	 * @return true if the mutex is locked at the time of the probe,
	 *         false otherwise.
	 */
	public boolean isLocked() {
		return (null != this.y);
	}

}
